package com.cruise.h5.util;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;

/**
 * 类名：DownLoadUtils
 * 描述：TODO
 * @author ：Cruise
 * 日期：2020/3/27 下午1:40
 * 版本：1.0
 **/
public class DownLoadUtils {

    private static Logger log = LogManager.getLogger(com.cruise.h5.util.DownLoadUtils.class);

    public static com.cruise.h5.util.DownLoadUtils me;

    private DownLoadUtils(){
        //单例
    }
    /**
     * 双重锁
     */

    public static com.cruise.h5.util.DownLoadUtils getInstance(){
        if (me==null) {
            synchronized (com.cruise.h5.util.DownLoadUtils.class) {
                if(me == null){
                    me = new com.cruise.h5.util.DownLoadUtils();
                }
            }
        }
        return me;
    }

    /**
     * 以流的方式下载
     * @param path
     * @param response
     * @return
     */
    public static HttpServletResponse download(String path, String filename , HttpServletRequest request, HttpServletResponse response) {
        try {

            // path是指欲下载的文件的路径。
            File file = new File(path);
            // 以流的形式下载文件。
            InputStream fis = new BufferedInputStream(new FileInputStream(path));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            response.reset();
            // 设置response的Header
            setFileDownloadHeader(request,response,filename);
            response.addHeader("Content-Length", "" + file.length());
            ServletOutputStream outputStream = response.getOutputStream();
            OutputStream toClient = new BufferedOutputStream(outputStream);
            response.setContentType("application/x-msdownload");
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
            outputStream.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return response;
    }

    public static  void setFileDownloadHeader(HttpServletRequest request, HttpServletResponse response, String fileName) {
      String userAgent = request.getHeader("USER-AGENT");
      String msie= "MSIE";
      String  mozilla = "Mozilla";
       try {
          String finalFileName = null;
            if (userAgent.contains(msie)) {
              // IE浏览器
              finalFileName = URLEncoder.encode(fileName, "UTF8");
            } else if (userAgent.contains(mozilla)) {
                // google,火狐浏览器
                finalFileName = new String(fileName.getBytes(), "ISO8859-1");
            } else {
                // 其他浏览器
                finalFileName = URLEncoder.encode(fileName, "UTF8");
            }
           // 这里设置一下让浏览器弹出下载提示框，而不是直接在浏览器中打开
            response.addHeader("Content-Disposition", "attachment; filename=\"" + finalFileName + "\"");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }



    public static void downRangeFile(String path, String filename,
                              HttpServletRequest request,
                                     HttpServletResponse response) throws Exception {

        int lastIndexOf = path.lastIndexOf(".");
        //获取文件的后缀名 .jpg
        String suffix = path.substring(lastIndexOf+1);

        // path是指欲下载的文件的路径。
        File downloadFile = new File(path);
        if (!downloadFile.exists()) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        long fileLength = downloadFile.length();// 记录文件大小
        long pastLength = 0;// 记录已下载文件大小
        int rangeSwitch = 0;// 0：从头开始的全文下载；1：从某字节开始的下载（bytes=27000-）；2：从某字节开始到某字节结束的下载（bytes=27000-39000）
        long contentLength = 0;// 客户端请求的字节总量
        String rangeBytes = "";// 记录客户端传来的形如“bytes=27000-”或者“bytes=27000-39000”的内容
        RandomAccessFile raf = null;// 负责读取数据
        OutputStream os = null;// 写出数据
        OutputStream out = null;// 缓冲
        int bsize = 1024;// 缓冲区大小
        byte b[] = new byte[bsize];// 暂存容器

        String range = request.getHeader("Range");
        int responseStatus = 206;
        if (range != null && range.trim().length() > 0 && !"null".equals(range)) {// 客户端请求的下载的文件块的开始字节
            responseStatus = javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT;
            System.out.println("request.getHeader(\"Range\")=" + range);
            rangeBytes = range.replaceAll("bytes=", "");
            if (rangeBytes.endsWith("-")) {
                rangeSwitch = 1;
                rangeBytes = rangeBytes.substring(0, rangeBytes.indexOf('-'));
                pastLength = Long.parseLong(rangeBytes.trim());
                contentLength = fileLength - pastLength;
            } else {
                rangeSwitch = 2;
                String temp0 = rangeBytes.substring(0, rangeBytes.indexOf('-'));
                String temp2 = rangeBytes.substring(rangeBytes.indexOf('-') + 1, rangeBytes.length());
                pastLength = Long.parseLong(temp0.trim());
            }
        } else {
            contentLength = fileLength;// 客户端要求全文下载
        }


        // 清除首部的空白行
        response.reset();
        // 告诉客户端允许断点续传多线程连接下载,响应的格式是:Accept-Ranges: bytes
        response.setHeader("Accept-Ranges", "bytes");
        // 如果是第一次下,还没有断点续传,状态是默认的 200,无需显式设置;响应的格式是:HTTP/1.1

        if (rangeSwitch != 0) {
            response.setStatus(responseStatus);
            // 不是从最开始下载，断点下载响应号为206
            // 响应的格式是:
            // Content-Range: bytes [文件块的开始字节]-[文件的总大小 - 1]/[文件的总大小]
            switch (rangeSwitch) {
                case 1: {
                    String contentRange = new StringBuffer("bytes ")
                            .append(new Long(pastLength).toString()).append("-")
                            .append(new Long(fileLength - 1).toString())
                            .append("/").append(new Long(fileLength).toString())
                            .toString();
                    response.setHeader("Content-Range", contentRange);
                    break;
                }
                case 2: {
                    String contentRange = range.replace("=", " ") + "/"
                            + new Long(fileLength).toString();
                    response.setHeader("Content-Range", contentRange);
                    break;
                }
                default: {
                    break;
                }
            }
        } else {
            String contentRange = new StringBuffer("bytes ").append("0-")
                    .append(fileLength - 1).append("/").append(fileLength)
                    .toString();
            response.setHeader("Content-Range", contentRange);
        }

        try {
            response.setContentType("video/"+suffix+";charset=UTF-8");
            response.setHeader("Content-Length", String.valueOf(contentLength));
            os = response.getOutputStream();
            out = new BufferedOutputStream(os);
            raf = new RandomAccessFile(downloadFile, "r");
            try {
                long outLength = 0;// 实际输出字节数
                switch (rangeSwitch) {
                    case 0: {
                    }
                    case 1: {
                        raf.seek(pastLength);
                        int n = 0;
                        while ((n = raf.read(b)) != -1) {
                            out.write(b, 0, n);
                            outLength += n;
                        }
                        break;
                    }
                    case 2: {
                        raf.seek(pastLength);
                        int n = 0;
                        long readLength = 0;// 记录已读字节数
                        while (readLength <= contentLength - bsize) {// 大部分字节在这里读取
                            n = raf.read(b);
                            readLength += n;
                            out.write(b, 0, n);
                            outLength += n;
                        }
                        if (readLength <= contentLength) {// 余下的不足 1024 个字节在这里读取
                            n = raf.read(b, 0, (int) (contentLength - readLength));
                            out.write(b, 0, n);
                            outLength += n;
                        }
                        break;
                    }
                    default: {
                        break;
                    }
                }
                System.out.println("Content-Length为：" + contentLength + "；实际输出字节数：" + outLength);
                out.flush();
            } catch (IOException ie) {
                // ignore
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (raf != null) {
                try {
                    raf.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }


}
